package com.gomoney.auth.security.config;


import com.gomoney.auth.security.service.UserDetailsServiceImpl;
import com.gomoney.auth.security.util.SysUserJwtAccessTokenConverter;
import com.gomoney.auth.security.service.UserDetailsServiceImpl;
import com.gomoney.auth.security.util.SysUserJwtAccessTokenConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
import org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory;

import java.security.KeyPair;

/**
 * @Description //TODO
 * 授权的配置
 * token 存放在redis
 * 配置第三方redis
 * @Author zhangyong
 * @Date 2021/4/23 13:58
 **/
@Configuration
public class AuthorizationJWTConfig extends AuthorizationServerConfigurerAdapter {
    /**
     * @Description 注入认证管理器
     * @Author zhangyong
     * @Date 2021/4/25 15:10
     **/
    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    PasswordEncoder passwordEncoder;

    @Autowired
    private RedisConnectionFactory connectionFactory;

    /**
     * @Description //TODO
     * @Author zhangyong
     * jwt 的token转换器
     * 把用户信息转成jwt的形式颁发出去
     * @Date 2021/4/26 15:23
     **/
    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter() {
        JwtAccessTokenConverter jwtAccessTokenConverter = new SysUserJwtAccessTokenConverter();
		/* 需要一个sign签名, 这叫对称加密
		jwtAccessTokenConverter.setSigningKey( "whsxt-cxs-oauth2" );
		*/
        // 非对称加密
        //1.文件读进来
        ClassPathResource resource = new ClassPathResource("cxs-jwt.jks");
        //2.创建钥匙工厂
        KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(resource, "cxs123".toCharArray());
        //3.通过别名拿到私钥
        KeyPair keypair = keyStoreKeyFactory.getKeyPair("cxs-jwt");
        //4.设置进去
        jwtAccessTokenConverter.setKeyPair(keypair);
        return jwtAccessTokenConverter;
    }

    @Autowired
    private UserDetailsServiceImpl userDetailService;

    @Bean
    public JwtTokenStore tokenStore() {
        return new JwtTokenStore(jwtAccessTokenConverter());
    }

/*    @Bean
    public TokenStore tokenStore() {
        return new InMemoryTokenStore();
    }*/

/*    @Bean
    public TokenStore tokenStore(final RedisConnectionFactory factory) {
        return new RedisTokenStore(factory);
    }*/

/*    @Bean
    public TokenStore tokenStore() {
        return new RedisTokenStore(connectionFactory);
    }*/

    /**
     * @Description 需要暴露授权服务给token的存储
     * 暴露授权服务器给认证管理器
     * 暴露服务
     * @Author zhangyong
     * @Date 2021/4/23 14:21
     **/
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenStore(tokenStore()).
                userDetailsService(userDetailService).
                authenticationManager(authenticationManager)
                .accessTokenConverter(jwtAccessTokenConverter());
    }

    /**
     * @Description //TODO
     * <p>
     * 配置第三方应用
     * 四种授权:
     * get http://localhost:9999/oauth/authorize?response_type=code&client_id=web&state=sxt&redirect_uri=https://www.baidu.com
     * return https://www.baidu.com/?code=r8BwW2&state=sxt
     * post http://localhost:9999/oauth/token?grant_type=authorization_code&code=kebH3N&redirect_uri=https://www.baidu.com
     * 1.code授权码 authorization_code
     * get http://localhost:9999/oauth/authorize?response_type=token&client_id=wx&state=sxt&redirect_uri=https://www.baidu.com
     * return https://www.baidu.com/#access_token=44c2b66f-6f88-45c0-aed8-abcc4f8c3f29&token_type=bearer&state=sxt&expires_in=3023&scope=all
     * 2.静默授权  implicit
     * get http://localhost:9999/oauth/token?grant_type=password&username=whsxt&password=whsxt
     * Authoriaztion: Basic Auth : qq/qq-secret
     * 3.密码授权  password
     * post http://localhost:9999/oauth/token?grant_type=client_credentials
     * Authoriaztion: Basic Auth : client/cleint-secret
     * 4.客户端授权（直接通过浏览器就能获取token ） client_credentials
     * @Author zhangyong
     * @Date 2021/4/23 14:11
     **/
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                .withClient("web")//第三方应用的客户端ID
                .secret(passwordEncoder.encode("web-secret"))
                .scopes("read") //配置第三方应用的作用域
                .authorizedGrantTypes("authorization_code")//授权类型 4种
                .accessTokenValiditySeconds(7200)// token的有效时间
                .redirectUris("https://www.baidu.com") //授权后跳转的URL地址
                .and()
                .withClient("wx")
                .secret(passwordEncoder.encode("wx-secret"))
                .scopes("all")
                .authorizedGrantTypes("implicit") //静默授权
                .accessTokenValiditySeconds(3600)
                .redirectUris("https://www.baidu.com")
                .and()
                .withClient("qq")
                .secret(passwordEncoder.encode("qq-secret"))
                .scopes("all")
                .authorizedGrantTypes(
                        "refresh_token",
                        "password")
                .accessTokenValiditySeconds(3600)
                .refreshTokenValiditySeconds(604800)
                .redirectUris("https://www.baidu.com")
                .and()
                .withClient("client")
                .secret(passwordEncoder.encode("client-secret"))
                .scopes("readOnly")
                .authorizedGrantTypes("client_credentials")
                .accessTokenValiditySeconds(500)
                .redirectUris("https://www.baidu.com");
    }
}
